﻿// Расширение monitor вложенным пространством имен gmap.    
monitor.gmap = monitor.gmap || {};
  
monitor.gmap.utils = {};
monitor.gmap.utils._boxingGoogleCoords = function(googleCoords) {
    var selfCoords = [];
    for (var i = 0; i < googleCoords.length; i++) {
        selfCoords.push({ X: googleCoords[i].lat(), Y: googleCoords[i].lng() });
    }
    return selfCoords;
};

/* ----- Map -----*/
(function () {

    // Конструктор класса Map
    //   ( mapContainerId - идентификатр HTML-контейнера для карты;
    //     mapOpts        - объект класса google.maps.MapOptions )
    //
    monitor.gmap.Map = function(mapContainerId, mapOpts) {
        this.googleMap = null;
        this.eventListener = null;
        var self = this;

        // Координаты Минска.
        // var latlngCenter = new google.maps.LatLng(53.916666676667, 27.55000001);
        // Географический центр Беларуси.
        //var latlngBelarusCenter = new google.maps.LatLng(53.315076, 28.238);

        // Параметры карты по умолчанию.
        var defMapOpts = {
            zoom: 8, // масштаб
            center: new google.maps.LatLng(0, 0), // пересечение экватора и нулевого меридиана
            streetViewControl: false, // панорамный вид не требуется
            scaleControl: true, // показать шкалу масштаба
            mapTypeId: google.maps.MapTypeId.ROADMAP // тип карты по умолчанию 
        };
        
        initMap();

       /* this.getGoogleMap = function() {
            return googleMap;
        };*/

        // Функция инициализации объекта Map. 
        function initMap() {
            mapOpts = mapOpts || {}; 
            // Получение параметров, с которыми будет создана карта. Если требуемый параметр не передан конструктору Map,
            // то он берется из параметров, заданных по умолчанию.
            //
            var mapOptions = {
                zoom: (mapOpts.mapZoom !== undefined)
                          ? mapOpts.mapZoom
                          : defMapOpts.zoom,
                center: (mapOpts.mapCenter !== undefined)
                            ? new google.maps.LatLng(mapOpts.mapCenter.lat, mapOpts.mapCenter.lng)
                            : defMapOpts.center,
                streetViewControl: (mapOpts.streetViewControl !== undefined)
                                       ? mapOpts.streetViewControl
                                       : defMapOpts.streetViewControl,
                scaleControl: (mapOpts.scaleControl !== undefined)
                                  ? mapOpts.scaleControl
                                  : defMapOpts.scaleControl,
                mapTypeId: (mapOpts.mapType !== undefined)
                               ? google.maps.MapTypeId[mapOpts.mapType]
                               : defMapOpts.mapTypeId
            };
            // Создание карты внутри HTML-контейнера, заданного идентификатором mapContainerId.
            self.googleMap = new google.maps.Map(document.getElementById(mapContainerId), mapOptions);
            self.eventListener = monitor.gmap.event.eventListener();

            // Событие нажатия левой клавиши мыши на карте.
            google.maps.event.addListener(self.googleMap, 'click', function (event) {
                var mouseEvent = {};
                mouseEvent.coord = {
                    X: event.latLng.lat(),
                    Y: event.latLng.lng()
                };
                self.eventListener.trigger('click', mouseEvent);
            });
            // Событие перемещения мыши по карте.
            google.maps.event.addListener(self.googleMap, 'mousemove', function (event) {
                var mouseEvent = {};
                mouseEvent.coord = {
                    X: event.latLng.lat(),
                    Y: event.latLng.lng()
                };
                self.eventListener.trigger('mousemove', mouseEvent);
            });
            // Обработчик для события 'resize' (вызывается извне)
            self.eventListener.on('resize', function () {
                google.maps.event.trigger(self.googleMap, 'resize');
            });
        };
    };

    // Прототип класса Map
    //
    monitor.gmap.Map.prototype = {
        // Показать выбранную область на всю карту.
        fitArea: function(area) {
            var path = area.getPath();
            var latDown = path.getAt(0).lat();
            var latUp = latDown;
            var lngLeft = path.getAt(0).lng();
            var lngRight = lngLeft;
            for (var i = 0; i < path.length; i++) {
                var latlng = path.getAt(i);
                if (latlng.lat() < latDown) {
                    latDown = latlng.lat();
                } else if (latlng.lat() > latUp) {
                    latUp = latlng.lat();
                }
                if (latlng.lng() < lngLeft) {
                    lngLeft = latlng.lng();
                } else if (latlng.lng() > lngRight) {
                    lngRight = latlng.lng();
                }
            }

            var bounds = new google.maps.LatLngBounds(
                new google.maps.LatLng(latDown, lngLeft),
                new google.maps.LatLng(latUp, lngRight));

            this.googleMap.fitBounds(bounds);
        },
        // Установка курсора, отображаемого при наведении на карту.
        setMapCursor: function (cursor) {
            this.googleMap.setOptions({ draggableCursor: cursor });
        },
        on: function (eventName, handler) {
            this.eventListener.on(eventName, handler);
        },
        off: function (eventName, handler) {
            this.eventListener.off(eventName, handler);
        },
        trigger: function (eventName) {
            //this.eventListener.trigger.apply(this, [].slice.call(arguments, 1));
            this.eventListener.trigger(eventName, [].slice.call(arguments, 1));
        },
        /*// Вызвать обработчик для запрашиваемого события. 
        triggerEvent: function(eventName) {
            google.maps.event.trigger(this.googleMap, eventName);
        }*/
    };
    
})();

/* ----- Marker -----*/
(function () {

    // Конструктор класса Marker
    // ( параметр markerOpts.map обязателен )
    //
    monitor.gmap.Marker = function(markerOpts) {
        this.mountMap = markerOpts.map.googleMap; // карта, на которую "крепится" маркер
        this.googleMarker = null;
        this.eventListener = null;
        var self = this;

        markerOpts = markerOpts || {};
        var markerOptions = {
            map: this.mountMap,
            position: (markerOpts.latlng !== undefined)
                       ? new google.maps.LatLng(markerOpts.latlng.x, markerOpts.latlng.y)
                       : null,
            title: (markerOpts.title !== undefined)
                       ? markerOpts.title
                       : '',
            animation: (markerOpts.animation !== undefined)
                       ? google.maps.Animation[markerOpts.animation]
                       : null,
            draggable: (markerOpts.draggable !== undefined)
                       ? markerOpts.draggable
                       : false,
            clickable: (markerOpts.clickable !== undefined)
                       ? markerOpts.clickable
                       : true,
            cursor: (markerOpts.cursor !== undefined)
                       ? markerOpts.cursor
                       : 'pointer',
            visible: false
        };

        this.googleMarker = new google.maps.Marker(markerOptions);
        self.eventListener = monitor.gmap.event.eventListener();
       
        google.maps.event.addListener(this.googleMarker, 'click', function() {
            self.eventListener.trigger('click');
            /*if (self.marker.info) {
                self.marker.info.open(self.mountMap, self.marker);
            };*/
        });
    };

    // Прототип класса Marker
    monitor.gmap.Marker.prototype = {
        show: function () {
            this.googleMarker.setVisible(true);
        },
        hide: function () {
            this.googleMarker.setVisible(false);
        },
        setPosition: function (latlng) {
            this.googleMarker.setPosition(new google.maps.LatLng(latlng.x, latlng.y));
        },
        setIcon: function(icon) {
            this.googleMarker.setIcon(icon);
            //this.marker.setIcon(figure.icon);
           // this.marker.setShadow(figure.shadow);
        },
        /*setInfoWindow: function (infoWindow) {
            this.marker.info = infoWindow;
        }*/
        on: function (eventName, handler) {
            this.eventListener.on(eventName, handler);
        },
        off: function (eventName, handler) {
            this.eventListener.off(eventName, handler);
        },
        trigger: function (eventName) {
            this.eventListener.trigger(eventName);
        },
    };

/*
    Marker.prototype.setPosition = function(latlng) {
        this.marker.setPosition(new google.maps.LatLng(latlng.X, latlng.Y));
    };
    Marker.prototype.setCenterPosition = function(latlng) {
        this.marker.setPosition(new google.maps.LatLng(latlng.X, latlng.Y));
        this.mountMap.setCenter(new google.maps.LatLng(latlng.X, latlng.Y));
    };
    Marker.prototype.setInfoContent = function(contentHtml) {
        this.marker.info.setContent(contentHtml);
    };
    Marker.prototype.hideMarker = function() {
        this.marker.setMap(null);
    };
    Marker.prototype.setIcon = function(figure) {
        this.marker.setIcon(figure.icon);
        this.marker.setShadow(figure.shadow);
    };
    Marker.prototype.placeSimpleMarker = function(latlng) {
        delete this.marker.info;
        this.marker.setMap(this.mountMap);
        this.setPosition(latlng);
    };
    Marker.prototype.placeCenterMarker = function(latlng) {
        this.placeSimpleMarker(latlng);
        this.mountMap.setCenter(new google.maps.LatLng(latlng.X, latlng.Y));
    };
    Marker.prototype.placeInfoMarker = function(latlng, infoContent) {
        this.placeSimpleMarker(latlng);
        this.marker.info = new google.maps.InfoWindow({
            content: infoContent
        });
    };
    Marker.prototype.placeCenterInfoMarker = function(latlng, infoContent) {
        this.placeCenterMarker(latlng);
        this.marker.info = new google.maps.InfoWindow({
            content: infoContent
        });
    };*/
})();

/* ----- Polyline -----*/
(function () {

    // Конструктор класса Polyline
    // ( параметр lineOpts.map обязателен )
    //
    monitor.gmap.Polyline = function (lineOpts) {
        this.mountMap = lineOpts.map.googleMap; // карта, на которой отображается ломаная линия
        this.googlePolyline = null;
        this.eventListener = null;
        var self = this;

        lineOpts = lineOpts || {};
        var lineOptions = {
            map: this.mountMap,
            strokeColor: (lineOpts.color !== undefined)
                       ? lineOpts.color
                       : "00FF00",
            strokeOpacity: (lineOpts.opacity !== undefined)
                       ? lineOpts.opacity
                       : 1.0,
            strokeWeight: (lineOpts.weight !== undefined)
                       ? lineOpts.weight
                       : 2,
            icons: (lineOpts.icon !== undefined)
                    ? [{
                            icon: 
                            {
                                path: (lineOpts.icon.path !== undefined)
                                    ? lineOpts.icon.path
                                    : 'M -.25,-.25 .25,-.25, .25,.25 -.25,.25',
                                fillOpacity: (lineOpts.icon.opacity !== undefined)
                                    ? lineOpts.icon.opacity
                                    : 1.0,
                                fillColor: (lineOpts.icon.color !== undefined)
                                    ? lineOpts.icon.color
                                    : 'blue',
                            },
                            repeat: (lineOpts.icon.repeat !== undefined)
                                ? lineOpts.icon.repeat
                                : '6px',
                      }]
                    : null,
        };

        this.googlePolyline = new google.maps.Polyline(lineOptions);
        this.eventListener = monitor.gmap.event.eventListener();
        
        google.maps.event.addListener(self.googlePolyline, 'click', function (event) {
            var mouseEvent = {};
            mouseEvent.coord = {
                X: event.latLng.lat(),
                Y: event.latLng.lng()
            };
            self.eventListener.trigger('click', mouseEvent);
        });
    };

    // Прототип класса Polyline
    monitor.gmap.Polyline.prototype = {
        erase: function () {
            this.googlePolyline.setPath([]);
        },
        addVertex: function (vert) {
            var path = this.googlePolyline.getPath();
            path.push(new google.maps.LatLng(vert.X, vert.Y));
        },
        on: function (eventName, handler) {
            this.eventListener.on(eventName, handler);
        },
        off: function (eventName, handler) {
            this.eventListener.off(eventName, handler);
        },
        trigger: function (eventName) {
            this.eventListener.trigger(eventName);
        },
    };
})();

/* ----- AreaPoly -----*/
(function () {

    // Конструктор класса AreaPoly
    // ( параметр areaOpts.map обязателен )
    //
    monitor.gmap.AreaPoly = function(areaOpts) {
        this.mountMap = areaOpts.map.googleMap; // карта, на которой отображается зона
        this.googlePoly = null;
        this.eventListener = null;
        var self = this;

        areaOpts = areaOpts || {};
        var areaOptions = {
            map: this.mountMap,
            strokeColor: (areaOpts.borderColor !== undefined)
                       ? areaOpts.borderColor
                       : "00FF00",
            strokeOpacity: (areaOpts.borderOpacity !== undefined)
                       ? areaOpts.borderOpacity
                       : 0.8,
            strokeWeight: (areaOpts.borderWeight !== undefined)
                       ? areaOpts.borderWeight
                       : 2,
            fillColor: (areaOpts.fillColor !== undefined)
                       ? areaOpts.fillColor
                       : "00FF00",
            fillOpacity: (areaOpts.fillOpacity !== undefined)
                       ? areaOpts.fillOpacity
                       : 0.5,
            visible: false,
            editable: (areaOpts.editable !== undefined)
                       ? areaOpts.editable
                       : false,
        };
       
        this.googlePoly = new google.maps.Polygon(areaOptions);
        this.eventListener = monitor.gmap.event.eventListener();
        // Событие перемещения мыши по области.
        google.maps.event.addListener(self.googlePoly, 'mousemove', function (event) {
            var mouseEvent = {};
            mouseEvent.coord = {
                X: event.latLng.lat(),
                Y: event.latLng.lng()
            };
            self.eventListener.trigger('mousemove', mouseEvent);
        });
    };

    // Прототип класса AreaPolygon
    monitor.gmap.AreaPoly.prototype = {
        // Показать зону на карте.
        show: function () {
            this.googlePoly.setVisible(true);
        },
        // Скрыть зону с карты.
        hide: function () {
            this.googlePoly.setVisible(false);
        },
        // Сформировать зону из переданных координат ее вершин.
        shapeArea: function (coords) {
            var path = [];
            for (var i = 0; i < coords.length; i++) {
                path.push(new google.maps.LatLng(coords[i].X, coords[i].Y));
            }
            this.googlePoly.setPath(path);
            //this.googlePoly.setMap(this.mountMap);
            //this.show();
        },
        // Добавление вершины в конец упорядоченной последовательности соединенных вершин зоны,
        // замкнутый контур перестраивается.
        addVertex: function (vertCoord) {
            var areaPath = this.googlePoly.getPath();
            areaPath.push(new google.maps.LatLng(vertCoord.X, vertCoord.Y));
        },
        // Очистить сформированную зону, зона с карты убирается.
        clearArea: function () {
            this.googlePoly.setPath([]);
            //this.googlePoly.setMap(null);
        },
        getCoords: function () {
            return monitor.gmap.utils._boxingGoogleCoords(this.googlePoly.getPath().getArray());
        },
        on: function (eventName, handler) {
            this.eventListener.on(eventName, handler);
        },
        off: function (eventName, handler) {
            this.eventListener.off(eventName, handler);
        },
        trigger: function (eventName) {
            this.eventListener.trigger(eventName);
        },
    };
})();

/* ----- InfoWindow -----*/
(function () {
    // Конструктор класса InfoWindow
    //
    monitor.gmap.InfoWindow = function (content) {

        this.infowindow = new google.maps.InfoWindow({
            content: content    
        });
    };
    // Прототип класса InfoWindow
    monitor.gmap.InfoWindow.prototype = {
        setInfoContent: function(content) {
            this.infowindow.setContent(content);
        },
        getInfoContent: function () {
            return this.infowindow.getContent();
        },
        open: function (map, anchor) {
            this.infowindow.open(map, anchor);
        },
        close: function () {
            this.infowindow.close();
        }
    };
})();
    
/* ----- MarkerIcon -----*/
(function () {
   
    // Конструктор класса MarkerImage
    // (параметр iconOpts.urlPath обязателен)
    //
    monitor.gmap.MarkerIcon = function (iconOpts) {
        iconOpts = iconOpts || {};

        // Параметры, с которыми будет создано изображение для маркера. 
        //
        var iconOptions = {
            url: iconOpts.urlPath,
            size: (iconOpts.size !== undefined)
                      ? new google.maps.Size(iconOpts.size.w, iconOpts.size.h)
                      : null,
            origin: (iconOpts.origin !== undefined)
                        ?  new google.maps.Point(iconOpts.origin.x, iconOpts.origin.y)
                        : null,
            anchor: (iconOpts.anchor !== undefined)
                        ? new google.maps.Point(iconOpts.anchor.x, iconOpts.anchor.y)
                        : null
        };

        return new google.maps.MarkerImage(iconOptions.url, iconOptions.size, iconOptions.origin, iconOptions.anchor);
    };
    
})();
    
    